﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Text;

namespace ycdlib
{
	/// <summary>
	/// YCDocument
	/// </summary>
	public class YCDocument
	{
		public List<YCNode>	Children;
		private YCReaderSetting setting;

		/// <summary>
		/// ファイルから読み込む
		/// </summary>
		/// <param name="filename">ファイル名</param>
		/// <returns>YCDocumentオブジェクトを返す</returns>
		public static YCDocument ReadFile ( string filename )
		{
			//return Read( System.IO.File.ReadAllText( filename ) );
			return YCParser.ParseFile( filename );
		}

		/// <summary>
		/// 文字列から読み込む
		/// </summary>
		/// <param name="str">ドキュメント文字列</param>
		/// <returns></returns>
		public static YCDocument Read ( string str )
		{
			return YCParser.Parse( str );
			//YCReaderSetting __readerSetting = new YCReaderSetting();
			//YCDocument result = Parser.Parse( str, __readerSetting );
			//return result;
		}


		public YCDocument ( YCReaderSetting setting )
		{
			this.setting = setting;
		}

		/// <summary>
		/// ファイルに書き出す
		/// </summary>
		/// <param name="filename">出力するファイル名</param>
		public void Write ( string filename )
		{
			FileStream fs = null;

			try
			{
				fs = File.Open( filename, File.Exists( filename ) ? FileMode.Truncate : FileMode.Open, FileAccess.Write, FileShare.Read );
				Write( fs );
			}finally
			{
				if( fs != null )	fs.Dispose();
			}
		}


		/// <summary>
		/// 文字列に書き出す
		/// </summary>
		/// <returns>文字列を返す</returns>
		public string Write ()
		{
			string result;
			using( MemoryStream ms = new MemoryStream() )
			{
				Write( ms );
				result = Encoding.UTF8.GetString( ms.GetBuffer() );
			}
			return result;
		}


		/// <summary>
		/// ストリームに書き出す
		/// </summary>
		/// <param name="s"></param>
		/// <returns></returns>
		public void Write ( Stream s )
		{
			using( StreamWriter sw = new StreamWriter( s, Encoding.UTF8 ) )
			{
				//	TODO:書き出せ！
				int I = Children.Count;
				for( int i=0 ; i<I ; ++i )
				{
					Children[i].Write( s, 0 );
				}
				sw.Close();
			}
		}


		/// <summary>
		/// 指定されたパスの値を探す
		/// </summary>
		/// <param name="path">値を探すパス</param>
		/// <returns>YCNodeオブジェクトを返す。見つからなかったらNULL</returns>
		public YCNode FindValue ( string path )
		{
			//YCNode result = null;

			Path __path = new Path( path );
			string k = __path[0];
			int I = Children.Count;
			for( int i=0 ; i<I ; ++i )
			{
				if( k.Equals( Children[i].Name ) )
				{
					if( __path.Depth == 1 )
						return Children[i];
					else
					{
						YCNode result = findValue( Children[i], __path, 1 );
						if( result != null ) return result;
					}
				}
			}

			throw new NotImplementedException();
			//return result;
		}


		private YCNode findValue ( YCNode n, Path p, int depth )
		{
			string k = p[depth];
			if( n is YCNodeAnother )
			{
				YCNodeAnother na = (YCNodeAnother)n;
				int I = n.ChildCount;
				for( int i=0 ; i<I ; ++i )
				{
					if( k.Equals( na[i].Name ) )
					{
						if( p.Depth == (depth+1) )
							return na[i];
						else
						{
							YCNode result = findValue( na[i], p, depth+1 );
							if( result != null ) return result;
						}
					}
				}
			}
			return null;
		}


		/// <summary>
		/// 指定されたパスの値を探す
		/// </summary>
		/// <param name="path">値を探すパス</param>
		/// <returns>YCNodeオブジェクトを返す。見つからなかったらNULL</returns>
		public List<YCNode> FindValues ( string path )
		{
			//List<YCNode> result = null;

			throw new NotImplementedException();
			//return result;
		}


		public YCNode CreateNode ( string type, YCNode parent )
		{
			NodeCreator nc = null;
			YCNode __result = null;
			if( setting.TryGetCreator( type, out nc ) )
			{
				__result = nc.Invoke( parent );
			}else
			{
				__result = new YCNodeAnother( type, parent );
			}
			return __result;
		}
	}
}
